package com.mye.prometheusexportdcim.model.common;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.NumberUtil;
import com.mye.prometheusexportdcim.model.gaugeMetric.SnmpInfo;
import com.mye.prometheusexportdcim.utils.LogLocalityUtil;
import com.mye.prometheusexportdcim.utils.SnmpUtil;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.PDU;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

/**
 * @author hch
 * @创建人 hch
 * @创建时间 2021/6/28 16:04
 * @描述 TODO
 * @版本 1.0.0
 */
@Slf4j
public class GetSnmpInfoTask implements Callable<List<SnmpInfo>>, Cloneable {

    private String snmpAddress;

    /**
     * snmp协议类型
     */
    private int snmpProtocol;


    private List<String> oids;


    private String username;
    private String encryptionWay;
    private String encryptionPassword;
    private String authWay;
    private String authPassword;


    public GetSnmpInfoTask() {

    }


    public String getSnmpAddress() {
        return snmpAddress;
    }

    public void setSnmpAddress(String snmpAddress) {
        this.snmpAddress = snmpAddress;
    }

    public int getSnmpProtocol() {
        return snmpProtocol;
    }

    public void setSnmpProtocol(int snmpProtocol) {
        this.snmpProtocol = snmpProtocol;
    }

    public List<String> getOids() {
        return oids;
    }

    public void setOids(List<String> oids) {
        this.oids = oids;
    }


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEncryptionWay() {
        return encryptionWay;
    }

    public void setEncryptionWay(String encryptionWay) {
        this.encryptionWay = encryptionWay;
    }

    public String getEncryptionPassword() {
        return encryptionPassword;
    }

    public void setEncryptionPassword(String encryptionPassword) {
        this.encryptionPassword = encryptionPassword;
    }

    public String getAuthWay() {
        return authWay;
    }

    public void setAuthWay(String authWay) {
        this.authWay = authWay;
    }

    public String getAuthPassword() {
        return authPassword;
    }

    public void setAuthPassword(String authPassword) {
        this.authPassword = authPassword;
    }

    public GetSnmpInfoTask(String snmpAddress, int snmpProtocol, List<String> oids) {
        this.snmpAddress = snmpAddress;
        this.snmpProtocol = snmpProtocol;
        this.oids = oids;
    }

    public GetSnmpInfoTask(String snmpAddress, int snmpProtocol, List<String> oids, String username, String encryptionWay, String encryptionPassword, String authWay, String authPassword) {
        this.snmpAddress = snmpAddress;
        this.snmpProtocol = snmpProtocol;
        this.oids = oids;
        this.username = username;
        this.encryptionWay = encryptionWay;
        this.encryptionPassword = encryptionPassword;
        this.authWay = authWay;
        this.authPassword = authPassword;
    }

    @Override
    public List<SnmpInfo> call() {

        if (CollectionUtil.isEmpty(oids)) {
            return null;
        }
        List<List<String>> split = ListUtil.split(oids, 100);
        Vector<VariableBinding> variableBindingsAll = new Vector<>();
        for (List<String> list : split) {
            ResponseEvent responseEvent = SnmpUtil.sendMessage(snmpAddress, snmpProtocol, PDU.GET, list, username, authWay, authPassword, encryptionWay, encryptionPassword);
            Vector<? extends VariableBinding> variableBindings = Optional.ofNullable(responseEvent).flatMap(s -> Optional.ofNullable(s.getResponse())).map(PDU::getVariableBindings).orElse(null);
            if (CollectionUtil.isNotEmpty(variableBindings)) {
                variableBindingsAll.addAll(variableBindings);
            }
        }

        SnmpInfo snmpInfoRoot = new SnmpInfo(snmpAddress);
        return getCollect(variableBindingsAll, snmpInfoRoot);
    }

    private List<SnmpInfo> getCollect(Vector<? extends VariableBinding> variableBindings, SnmpInfo snmpInfoRoot) {
        if (CollectionUtil.isEmpty(variableBindings)) {
            return null;
        }
        return variableBindings.stream().filter(Objects::nonNull).map(s -> {
            SnmpInfo snmpInfo = snmpInfoRoot.clone();
            OID oid = s.getOid();
            if (oid == null) {
                return null;
            }
            snmpInfo.setOid(oid.toString());
            Variable variable = s.getVariable();
            if (variable != null) {
                try {
                    snmpInfo.setValue(NumberUtil.parseDouble(variable.toString()));
                } catch (Exception e) {
                    log.error(LogLocalityUtil.getLogLocality() + "该oid的variable值不合法,地址是： " + snmpInfo.getSnmpAddress() + ", oid是: " + oid + ", 值是: " + variable);
                }

            }
            return snmpInfo;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    @Override
    public GetSnmpInfoTask clone() {
        try {
            return (GetSnmpInfoTask) super.clone();
        } catch (CloneNotSupportedException e) {
            return new GetSnmpInfoTask();
        }

    }
}
